/*
 * File:    ServicePipe.java
 * Created: 14-Apr-2006
 * Version: $Id: //depot/bitgate/bsse/src/bitgate/util/service/ServicePipe.java#1 $
 *
 * COPYRIGHT (C) 2006, Bitgate Software, LLC.  All Rights Reserved.
 *
 * software@bitgatesoftware.com
 */

package com.bitgate.util.service;

import static com.bitgate.util.debug.Debug.*;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;
import java.nio.channels.WritableByteChannel;

import com.bitgate.util.service.client.ClientContext;

/**
 * Service functionality is controlled via IPC to tell the server how to handle abrupt disconnections of clients, and forced
 * disconnections, shutdowns, or other types of connections.  Pipe communications can also be sent to the server to tell the
 * server to do something other than client-based info.  For instance, you can pipe a command directly to the server to tell
 * it to dump diagnostic data, or statistics on currently connected clients.  You can also use it to tell the server to
 * shut down or restart itself.  These piped commands are only available via IPC, so for a command to be done to the server,
 * the pipe object must be passed to each command that is used.  All class methods inside this helper class are static
 * members.
 * <p/>
 * Statistic dumping functionality and other IPC code will be added later, this code is currently here for proof-of-concept.
 *
 * @author Kenji Hollis &lt;kenji@bitgatesoftware.com&gt;
 * @version $Id: //depot/bitgate/bsse/src/bitgate/util/service/ServicePipe.java#1 $
 */
public class ServicePipe
{
    /**
     * This code handles sending a command to the server on which it is running.
     *
     * @param ipcPipe The current <code>Pipe</code> attached to the server.
     * @param command The command to send to the server.
     */
    private static void sendCommand(final Pipe ipcPipe, String cmd)
    {
    	String command = cmd + "\n";
		WritableByteChannel wbChannel = ipcPipe.sink();
		byte[] commandBytes = new byte[command.length()];
		ByteBuffer outBytes = ByteBuffer.wrap(commandBytes);
	
		outBytes.clear();
		outBytes.put(command.getBytes());
		outBytes.flip();
	
		try {
			if (isDebugEnabled()) {
				debug("Sending command '" + cmd + "' to service pipe.");
			}
			
		    wbChannel.write(outBytes);
		} catch(IOException e) {
			if (isDebugEnabled()) {
				debug("IOException trying to write to IPC (disconnected?): " + e.getMessage());
			}
		}
	
		outBytes = null;
		commandBytes = null;
    }

    /**
     * Disconnects a client from the server by force.
     *
     * @param cContext The <code>ClientContext</code> object to refer to.
     * @param ipcPipe The <code>Pipe</code> to talk to.
     */
    public static void disconnectSerial(ClientContext cContext, Pipe ipcPipe)
    {
    	cContext.getClientChannel().setIndicatorClosed();
    	sendCommand(ipcPipe, "D" + cContext.getSerialId());
    }

    /**
     * Registers a <code>Channel</code> for writing in the <code>Service</code> object.
     *
     * @param cContext The <code>ClientContext</code> object to refer to.
     * @param ipcPipe The <code>Pipe</code> to talk to.
     */
    public static void registerWrite(ClientContext cContext, Pipe ipcPipe)
    {
    	sendCommand(ipcPipe, "W" + cContext.getSerialId());
    }
    
    /**
     * Registers a <code>Channel</code> for reading and removes the writing service entry.
     * 
     * @param cContext The <code>ClientContext</code> object to refer to.
     * @param ipcPipe The <code>Pipe</code> to talk to.
     */
    public static void registerRead(ClientContext cContext, Pipe ipcPipe)
    {
    	sendCommand(ipcPipe, "R" + cContext.getSerialId());
    }

    /**
     * Shuts down the entire server.
     *
     * @param ipcPipe The <code>Pipe</code> to talk to.
     */
    public static void shutdownServer(Pipe ipcPipe)
    {
    	sendCommand(ipcPipe, "SD");
    }
}
